/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

import java.util.ArrayList;

/**
 *
 * @author Albert Alemany Font
 */
public class Reglas {

    private Trie t;
    int contador;
    int n;
    int max_beta;

    /** Constructor por defecto */
    public Reglas() {

        t = new Trie(new Nodo());
        contador = 0;
        max_beta = 0;
    }
    
    /**
     * Devuelve la 'n' del conjunto de reglas
     * @return int
     */
    public int getN() {
        return n;
    }
    
    /**
     * Se establece la n del conjunto de reglas, tomando por valor la n que se para como parámetro de la función.
     * @param int n
     */
    public void setN(int n) {
        this.n = n;
    }
    
    /**
     * Devuelve la beta máxima del conjunto de reglas.
     * @return int
     */
    public int getMaxBeta() {
        return max_beta;
    }

    /**
     * Devuelve cierto si existe alguna regla con Alpha = 'alpha', o falso en caso contrario.
     * @param char[] alpha
     * @return bool
     * @throws ExcepcionVavio
     */
    public boolean existeRegla(char[] alpha) throws ExcepcionVacio{
        if (t.Existe(String.valueOf(alpha))) return true;
        return false;
    }

    /**
     * Devuelve cierto si existe alguna regla con Alpha = 'alpha' y Beta = 'beta' en el trie 'tr', o falso en caso contrario.
     * @param Trie tr
     * @param char[] beta
     * @return bool
     * @throws ExcepcionVavio
     */
     public boolean existeReglaBeta2(Trie tr, char[] beta) throws ExcepcionVacio{
        if (tr.Existe(String.valueOf(beta))) return true;
        return false;
    }
 
    /**
     * Muestra por pantalla todas las alphas del conjunto de reglas.
     * @throws ExcepcionVavio
     */
    public void imprimirAlphas() throws ExcepcionVacio {
        t.imprimir();  
    }
    
    private String invertirString (String s) {
        String saux = "";
        int n1 = s.length();
        for (int i = n1-1; i >= 0; --i) {
            saux = saux + s.charAt(i);
        }
        return saux;
    }
    
    /**
     * Se añade la regla formada por Alpha = 'ralpha' invertida y beta = 'rbeta' invertida, actualizando su probabilidad asociada.
     * @param String ralpha
     * @param String rbeta
     */
    public void anadirRegla (String ralpha, String rbeta) {
        if (rbeta.length() > max_beta) {
            max_beta = rbeta.length();
        }
        ralpha = invertirString(ralpha);
        rbeta = invertirString(rbeta);
        t.insertarRegla(ralpha, rbeta, 1);
        ++contador;
    }

    /**
     * Se añade 'cont' veces la regla formada por Alpha = 'ralpha' invertida y beta = 'rbeta' invertida, actualizando su probabilidad asociada.
     * @param String ralpha
     * @param String rbeta
     */
    public void anadirRegla (String ralpha, String rbeta, int cont) {
        if (rbeta.length() > max_beta) {
            max_beta = rbeta.length();
        }
        ralpha = invertirString(ralpha);
        rbeta = invertirString(rbeta);
        t.insertarRegla(ralpha, rbeta, cont);
        ++contador;
    }
    
    /**
     * Devuelve un ArrayList de ssid, con todas las reglas del conjunto.
     * Cada regla consta de su alpha, su beta, el número de veces que aparece y su probabilidad asociada.
     * @return ArrayList<ssid> reglas
     */
    public ArrayList<ssid> obtenerReglas() {
        ArrayList<ssid> reglas = new ArrayList<ssid>();
        ArrayList<String> alphas = new ArrayList<String>();
        t.getPalabrasAlpha(alphas);

        for (int i = 0; i < alphas.size(); ++i) {
            ArrayList<String> betas = new ArrayList<String>();
            ArrayList<Integer> cont = new ArrayList<Integer>();
            Trie auxiliar = t.GetUltimoNodoAlpha(alphas.get(i));
            auxiliar.getPalabrasBeta(betas,cont);
            String alphaR = invertirString(alphas.get(i));
            for (int j = 0; j < betas.size(); ++j) {
                double d1 = cont.get(j);
                double d2 = contador;
                double probR = d1/d2;
                String betaR = invertirString(betas.get(j));
                int contR = cont.get(j);
                ssid R = new ssid(alphaR,betaR,contR,probR);
                reglas.add(R);
            }
        }
        return reglas;
    }

    /**
     * Devuelve la probabilidad asociada a la regla formada por Alpha = 'alpha' y Beta = 'beta'.
     * @param char[] alpha
     * @param char[] beta
     * @return double
     * @throws ExcepcionVavio
     */
    public double obtenerProb (char[] alpha, char[] beta) throws ExcepcionVacio {
        String ralpha = String.valueOf(alpha);
        String rbeta = String.valueOf(beta);

        if (t.TrieVacio()) return 0.0;
        if (t.Existe(ralpha)) {
            if (t.GetUltimoNodoAlpha(ralpha)!= null && t.GetUltimoNodoAlpha(ralpha).Existe(rbeta)) {
                double d1 = t.GetUltimoNodoAlpha(ralpha).GetUltimoNodoBeta(rbeta);
                double d2 = contador;
                return d1 / d2;
            }
        }
        return 0.0;
    }
    /**
     * Borra el conjunto de reglas y pone el 'contador' y 'max_beta' a 0.
     */
    public void borrarReglas() {
        t = new Trie(new Nodo());
        contador = 0;
        max_beta = 0;
    }

    public Trie getTrieBeta (String alpha) {
       return t.GetUltimoNodoAlpha(alpha);
    }


}